#include "render.hpp"
#include "logger.hpp"
#include "object_manager.hpp"

#include "ogre_render/ogre_render.hpp"
//include other render there if need

#include "f_engine.hpp"

using namespace std;

boost::shared_ptr<if_system_t> render_t::create(f_engine_t *engine)
{
    boost::shared_ptr<render_t> ret(new render_t(engine));
    logger::log(DEBUG, "[Render] Render system created.");
    return ret;
}

render_t::~render_t()
{
    logger::log(DEBUG, "[Render] Render system destruction...");

    stop();

    delete impl_;
}

render_t::render_t(f_engine_t *engine) :
    engine_(engine), impl_(NULL)
{
    config_t &config = engine->system<config_t> ();

    impl_ = new render_impl_t(config.tree.get<string> ("Engine.GraphEngineConfig"));
}

void render_t::start()
{
    logger::log(DEBUG, "[Render] Starting system.");

    //create render in separate thread
    render_thr_ = boost::thread(&render_t::render_thr, this);
}

void render_t::stop()
{
    logger::log(DEBUG, "[Render] Stopping system.");

    render_thr_.interrupt();

    if (render_thr_.joinable())
    {
        render_thr_.join();
    }
}

boost::tuple<boost::shared_ptr<scene_node_t>, vector3_t> render_t::create_entity(object_class_t &obj_class)
{
    return impl_->create_entity(obj_class);
}

scalar_t render_t::get_per_phisics_scale()
{
    return impl_->get_per_phisics_scale();
}

void render_t::create_camera(const std::string &name)
{
    impl_->create_camera(name);
}
void render_t::set_back_color(const color_t &color)
{
    impl_->set_back_color(color);
}
void render_t::set_near_clip_dist(float dist)
{
    impl_->set_near_clip_dist(dist);
}
void render_t::set_far_clip_dist(float dist)
{
    impl_->set_far_clip_dist(dist);
}
void render_t::set_camera(const vector3_t &pos)
{
    impl_->set_camera(pos);
}
void render_t::camera_look_at(const vector3_t &dir)
{
    impl_->camera_look_at(dir);
}

void render_t::set_ambient_light(const color_t &color)
{
    impl_->set_ambient_light(color);
}
void render_t::create_directional_light(const color_t &diffuse_color, const color_t &specular_color, const vector3_t &direction)
{
    impl_->create_directional_light(diffuse_color, specular_color, direction);
}

void render_t::render_thr()
{
    logger::thr_desc_t name_thr("render");

    logger::log(DEBUG, "[Render] Starting render loop thread.");

    impl_->prepare_render();

    boost::shared_ptr<scripting_instance_t> script = scripting_instance_t::create(engine_, "render_start_up.lua");

    script->register_common();
    script->register_render_api();

    //run script
    script->run_script();

    engine_->report_started();

    engine_->wait_all_systems();

    try
    {

        while (true)
        {
            boost::mutex::scoped_lock g(engine_->system<object_manager_t> ().objects_sync_locker_);

            boost::this_thread::interruption_point();

            impl_->render_one_frame();
        }

    }
    catch (boost::thread_interrupted)
    {
    }

    impl_->cleanup_render();

    logger::log(DEBUG, "[Render] Render thread interrupted normally.");
}
